using System;
using CKS.EBE.API;
using Microsoft.SharePoint;
using System.Diagnostics;

namespace CKS.EBE.WebControls
{
    public class CommentForm : BaseForm
    {
        protected string CommentVal { get { return TextBoxValue("idComment"); } }
        protected string CommentUrlVal { get { return TextBoxValue("idCommentUrl"); } }

        private bool _AllowAnonymousComments = true;
        private bool _CheckSpam = true;

        public bool CheckSpam
        {
            get { return _CheckSpam; }
            set { _CheckSpam = value; }
        }

        public bool AllowAnonymousComments
        {
            get { return _AllowAnonymousComments; }
            set { _AllowAnonymousComments = value; }
        }

        protected override void OnSubmit(object sender, EventArgs e)
        {
            try
            {
                bool anonymous = Context.User.Identity.IsAuthenticated == false;
                Debug.Write("Submitting comment form. User is anonymous=" + anonymous);

                bool bIsSpam = CheckForSpam();

                // only add the comment with elevatedprivileges if the user is anonymous
                if (AllowAnonymousComments && anonymous)
                    SPSecurity.RunWithElevatedPrivileges(delegate { AddComment(bIsSpam); });
                else
                    AddComment(bIsSpam);

                ResponseControl.Visible = true;
                FormControl.Visible = false;
            }
            catch (Exception ex)
            {
                Debug.Write("Error in OnSubmit adding the comment: " + ex);
                throw;
            }
        }

        private void AddComment(bool bIsSpam)
        {
            using (var site = new SPSite(SPContext.Current.Site.ID))
            using (SPWeb web = site.OpenWeb(SPContext.Current.Web.ID))
            {
                Debug.Write(string.Format("Adding comment (spam={0}) as webAdminUser? {1}", bIsSpam, web.UserIsWebAdmin));
                SPList posts = Helper.GetListByFolderName(web, Localization.GetListName(Localization.BlogList.Posts, web.Language));
                SPListItem post = posts.GetItemById(int.Parse(Page.Request["id"]));
                SPList comments = Helper.GetListByFolderName(web, Localization.GetListName(Localization.BlogList.Comments, web.Language));

                web.AllowUnsafeUpdates = true;
                // query no rows, so that an items.add is fast and does not have to get all existing comments
                var query = new SPQuery {RowLimit = 0};
                SPListItem newComment = comments.GetItems(query).Add();
                newComment["Body"] = CommentVal;
                newComment["PostTitle"] = post.ID;
                newComment["Title"] = NameVal;
                newComment["CommentUrl"] = CommentUrlVal;
                if (comments.Fields.ContainsField("EmailAddress"))
                    newComment["EmailAddress"] = EmailVal;
                else
                    Debug.Write("the comments list does not contain an emailaddress field");

                newComment.Update();
                int newCommentID = newComment.ID;
                Debug.Write(string.Format("Comment with ID {0} Added", newCommentID));

                web.AllowUnsafeUpdates = false;

                // call with elevated privileges, so we can set the moderation status
                bool commentsListNeedsUpdate = true;
                SPSecurity.RunWithElevatedPrivileges(() => commentsListNeedsUpdate = RecycleSpamApproveSpamFree(comments, newCommentID, bIsSpam));
                Trace.Write("commentListNeedsUpdate: " + commentsListNeedsUpdate);
            }
        }

        /// <summary>
        /// if moderation is enabled, approve the item if it is spamfree
        /// if comment is spam, recycle it
        /// </summary>
        /// <param name="commentsList"></param>
        /// <param name="newCommentID"></param>
        /// <param name="bIsSpam"></param>
        /// <returns>true if comment has not been recycled</returns>
        private static bool RecycleSpamApproveSpamFree(SPList commentsList, int newCommentID, bool bIsSpam)
        {
            bool commentsListNeedsUpdate = true;
            using (var elevatedSite = new SPSite(SPContext.Current.Site.ID))
            using (var elevatedWeb = elevatedSite.OpenWeb(SPContext.Current.Web.ID))
            {
                elevatedWeb.AllowUnsafeUpdates = true;
                var comments = elevatedWeb.Lists[commentsList.ID];
                var comment = comments.GetItemById(newCommentID);
                if (bIsSpam)
                {
                    if (BlogContext.Current.Settings.DeleteSpamComments)
                    {
                        Debug.Write("Deleting spam comment");
                        comment.Recycle();
                        commentsListNeedsUpdate = false;
                    }
                    else if (comments.EnableModeration)
                    {
                        Debug.Write("Setting comment moderation status to denied");
                        comment.ModerationInformation.Status = SPModerationStatusType.Denied;
                        comment.Update();
                    }
                }
                else if (comments.EnableModeration && BlogContext.Current.Settings.AutoApproveComments)
                {
                    Debug.Write("approving comment");
                    comment.ModerationInformation.Status = SPModerationStatusType.Approved;
                    comment.Update();
                }

                elevatedWeb.AllowUnsafeUpdates = false;
            }
            return commentsListNeedsUpdate;
        }

        private bool CheckForSpam()
        {
            if (!CheckSpam) return false;

            bool bIsSpam = false;

            if (!String.IsNullOrEmpty(BlogContext.Current.Settings.AkismetKey))
            {
                var api = new Joel.Net.Akismet(BlogContext.Current.Settings.AkismetKey, Web.Url, Page.Request.UserAgent);

                if (api.VerifyKey())
                {
                    Debug.Write("Verified API key");
                    var c = new Joel.Net.AkismetComment
                                {
                                    Blog = Web.Url,
                                    UserIp = Page.Request.UserHostAddress,
                                    UserAgent = Page.Request.UserAgent,
                                    Referrer = Page.Request.UrlReferrer.ToString(),
                                    CommentContent = CommentVal,
                                    CommentType = "comment",
                                    CommentAuthor = NameVal,
                                    CommentAuthorUrl = CommentUrlVal,
                                    CommentAuthorEmail = EmailVal
                                };
                    bIsSpam = api.CommentCheck(c);
                }
                else
                {
                    Debug.WriteLine("Invalid Akismet key");
                }
            }
            else
            {
                Debug.Write("No Akismet Key found");
            }

            Debug.Write("Comment is spam: " + bIsSpam);
            return bIsSpam;
        }
    }
}
